--dofile("util/preload.lua")

local skynet = require "skynet"
local socket = require "skynet.socket"
local sproto = require "sproto"
local sprotoloader = require "sprotoloader"
local object = require "object"

local WATCHDOG
local host
local proto_pack
local client_fd
local player_id

local CMD = {}
local REQUEST = {}
local clientReady = false

local function load_config(filename)
    --read data
    local fh = io.open(filename,"r")
    --编译代码
    local func, err = load(fh:read("*a"))
    fh:close()

    if err ~= nil then
        return false, err
    end
    --保护模式
    return pcall(func)
end

local function broadcast_package(pack, fd)
	local package = string.pack(">s2", pack)
	skynet.send(WATCHDOG, "lua", "broadcast", package, fd)
end

local function send_package(pack, fd)
	local package = string.pack(">s2", pack)
	socket.write(fd, package)
end

--[[
function REQUEST:dead()
	print("player dead", self.id)
	skynet.call("SIMPLEDB", "lua", "dead", self.id)
end
]]--

function REQUEST:ready()
	skynet.error(">>>> player ready:")
	skynet.error(self.name)

	player_id = skynet.call("SIMPLEDB", "lua", "ready", self.name)

	-- player_fd[player_id] = client_fd

	send_package(proto_pack("ready", {id=player_id, name=self.name}), client_fd)
	skynet.error(">>>>> db return:"..player_id)
	--无法登陆，密码错误或者已经在线
	-- if player_id < 0 then
	-- 	skynet.send(WATCHDOG, "lua", "close", client_fd)
	-- 	return
	-- end
end

--[[
function REQUEST:send_message()
	-- Echo to the sending client
	skynet.error(">>>> user send message:")
	skynet.error(self.send_id)
	skynet.error(self.receive_id)
	skynet.error(self.message)

	for i, v in pairs(clientReady) do
		skynet.error(i, v)
	end

	-- send message back to the client
	send_package(proto_pack("send_message", {send_id = self.send_id, receive_id = self.receive_id, message = self.message}), client_fd)

end

function REQUEST:get_player_list()
	skynet.error(">>>> user get_player_list:")
	--Get online players from simpledb instead of the hardcoded null list
	local player_list_remote = skynet.call("SIMPLEDB", "lua", "get_players")
	send_package(proto_pack("get_player_list", {player_list = player_list_remote}), client_fd)
end

function REQUEST:sync_players()
	skynet.error(">>>> State from player")
	
	local pos = {self.posX, self.posY, self.posZ}
	local rot = {self.rot1, self.rot2, self.rot3, self.rot4}

	skynet.call("SIMPLEDB", "lua", "update_player", self.id, "pos", pos)
	skynet.call("SIMPLEDB", "lua", "update_player", self.id, "rot", rot)

	broadcast_package(proto_pack("sync_players", {id = self.id, posX = self.posX, posY = self.posY, posZ = self.posZ, rot1 = self.rot1, rot2 = self.rot2, rot3 = self.rot3, rot4 = self.rot4, speed = self.speed, rotSpeed = self.rotSpeed, airBorne = self.airBorne }, -1))
end

function REQUEST:send_jump()
	skynet.error(">>>> send_jump:")
	--Broadcast Jump to every client
	broadcast_package(proto_pack("send_jump", {id = self.id}), client_fd)
end
--]]

local function request(name, args, response)
	local f = assert(REQUEST[name])
	local r = f(args)
	-- if response then
		-- skynet.error(">>>>>>>>>>> response:"..name)
		-- return response(r)
	-- end
end
--[[
function REQUEST:send_play_vfx()
	skynet.error(">>>> user send_play_vfx")
	skynet.error(self.id)
	broadcast_package(proto_pack("recv_play_vfx", {id = self.id}), client_fd)
end
--]]

skynet.register_protocol {
	name = "client",
	id = skynet.PTYPE_CLIENT,
	unpack = function (msg, sz)
		return host:dispatch(msg, sz)
	end,
	dispatch = function (fd, _, type, ...)
		--assert(fd == client_fd)	-- You can use fd to reply message
		skynet.ignoreret()	-- session is fd, don't call skynet.ret
		--skynet.trace()
		if type == "REQUEST" then
			args = ...
			skynet.error("=====================")
			skynet.error(args)
			skynet.error("=====================")


			local ok, result  = pcall(request, ...)
			if ok then
				if result then
					send_package(result, fd)
				end
			else
				skynet.error(result)
			end
		else
			assert(type == "RESPONSE")
			error "This example doesn't support request client"
		end
	end
}

function CMD.start(conf)
	local fd = conf.client
	local gate = conf.gate
	WATCHDOG = conf.watchdog
	client_fd = fd

	host = sprotoloader.load(1):host "package"
	proto_pack = host:attach(sprotoloader.load(2))

	skynet.call(gate, "lua", "forward", fd)
	print("fd is ------: ", fd)
end

function CMD.disconnect(fd)
	skynet.send("SIMPLEDB", "lua", "logout", player_id)
	local pack = proto_pack("logout", { id = player_id})
	broadcast_package(pack, fd)
	skynet.exit()
end

skynet.start(function()
	skynet.dispatch("lua", function(_,_, command, ...)
		local f = CMD[command]
		skynet.ret(skynet.pack(f(...)))
	end)
end)
